<html>
    <head>
        <title>工作单元管理器  IUnitOfWorkManager</title>
    </head>
    <body>
        <script>
            /*
                         四、工作单元管理器  IUnitOfWorkManager

                                    IUnitOfWorkManager是用于控制工作单元系统的主要服务。

                                    以下部分解释了如何直接使用此服务（而大多数时候你不需要）。



                                    1、开始一个新的工作单元   Begin a New Unit Of Work 

                                            IUnitOfWorkManager.Begin方法用于创建新的UOW范围。

                                            eg:  创建一个新的"非事务性"UOW范围

                                                using System.Threading.Tasks;
                                                using Volo.Abp.DependencyInjection;
                                                using Volo.Abp.Uow;

                                                namespace AbpDemo
                                                {
                                                    public class MyService : ITransientDependency
                                                    {
                                                        private readonly IUnitOfWorkManager _unitOfWorkManager;

                                                        public MyService(IUnitOfWorkManager unitOfWorkManager)
                                                        {
                                                            _unitOfWorkManager = unitOfWorkManager;
                                                        }
                                                        
                                                        public virtual async Task FooAsync()
                                                        {
                                                            using (var uow = _unitOfWorkManager.Begin( // 开启新的UOW范围，并且是非事务性的

                                                                requiresNew: true, isTransactional: false
                                                            ))
                                                            {
                                                                //...
                                                                
                                                                await uow.CompleteAsync();
                                                            }
                                                        }
                                                    }
                                                }

                                                ★、Begin方法获取以下可选参数：

                                                        ①、requiresNew（bool）：设置true以忽略周围的工作单元并使用提供的选项启动一个新的UOW。

                                                                                默认值为false。
                                                                                
                                                                                如果它是false并且有一个周围的UOW，Begin方法实际上并没有开始一个新的UOW，而是静默地参与现有的UOW。

                                                        ②、isTransactional（bool）。默认值为false。是否为事务性的UOW。
                                                        
                                                        ③、isolationLevel（IsolationLevel?）：用于设置数据库事务的隔离级别，如果UOW是事务性的。如果未设置，则使用默认配置值。

                                                        ④、TimeOut（int?）：用于设置此UOW的超时值。默认值为null并回退到默认配置值。



                                    2、当前的工作单元   The Current Unit Of Work

                                                如前面所述，UOW是代码无感知的。

                                              (1)、如何获取当前工作单元？

                                                            如果你需要访问当前工作单元，你可以使用IUnitOfWorkManager.Current属性。

                                                            eg: 获取当前UOW

                                                                using System.Threading.Tasks;
                                                                using Volo.Abp.DependencyInjection;
                                                                using Volo.Abp.Uow;

                                                                namespace AbpDemo
                                                                {
                                                                    public class MyProductService : ITransientDependency
                                                                    {
                                                                        private readonly IUnitOfWorkManager _unitOfWorkManager;

                                                                        public MyProductService(IUnitOfWorkManager unitOfWorkManager)
                                                                        {
                                                                            _unitOfWorkManager = unitOfWorkManager;
                                                                        }
                                                                        
                                                                        public async Task FooAsync()
                                                                        {
                                                                            var uow = _unitOfWorkManager.Current; // 获取当前UOW

                                                                            //...
                                                                        }
                                                                    }
                                                                }

                                                            ★、Current属性返回一个IUnitOfWork对象。

                                                            备注：

                                                            如果当前作用域没有Uow，当前工作单元可以是null.

                                                            如果你的类是传统的UOW类，则不会是null，你手动将其设为UOW或在UOW范围内调用，如前所述。
                                                   

                                                (2)、异步保存更改 SaveChangesAsync

                                                            IUnitOfWork.SaveChangesAsync()方法将所有更改保存到数据库中。

                                                            如果你使用的是EF Core，它的行为完全相同。

                                                            如果当前UOW是事务性的，即使保存的更改也可以在错误时回滚（对于支持的数据库提供程序）。

                                                            eg: 插入实体以获取其自动增量ID后保存更改
                                                   

                                                                using System.Threading.Tasks;
                                                                using Volo.Abp.Application.Services;
                                                                using Volo.Abp.Domain.Repositories;

                                                                namespace AbpDemo
                                                                {
                                                                    public class CategoryAppService : ApplicationService, ICategoryAppService
                                                                    {
                                                                        private readonly IRepository<Category, int> _categoryRepository;

                                                                        public CategoryAppService(IRepository<Category, int> categoryRepository)
                                                                        {
                                                                            _categoryRepository = categoryRepository;
                                                                        }

                                                                        public async Task<int> CreateAsync(string name)
                                                                        {
                                                                            var category = new Category {Name = name};
                                                                            await _categoryRepository.InsertAsync(category); 
                                                                            
                                                                            // 保存更改，以便获取自动递增的ID
                                                                            await UnitOfWorkManager.Current.SaveChangesAsync();
                                                                            
                                                                            return category.Id;
                                                                        }
                                                                    }
                                                                }

                                                            此示例对Category实体使用自动增量int主键。自动增量PK"需要将实体保存到数据库"以获取新实体的id。
                                                        
                                                            此示例是从基ApplicationService类派生的应用程序服务，

                                                            该类已经将IUnitOfWorkManager服务作为UnitOfWorkManager属性注入。因此，无需手动注入。

                                                            由于获取当前UOW非常常见，因此还有一个CurrentUnitOfWork属性作为UnitOfWorkManager.Current的快捷方式。

                                                            因此，可以更改上面的示例以使用它：

                                                                await CurrentUnitOfWork.SaveChangesAsync();


                                                            ★、保存更改的替代方案 

                                                                        由于经常需要在插入、更新或删除实体后保存更改，因此相应的repository方法有一个可选的autoSave参数。

                                                                        因此，上面的CreateAsync方法可以重新编写，如下所示：

                                                                            public async Task<int> CreateAsync(string name)
                                                                            {
                                                                                var category = new Category {Name = name};
                                                                                await _categoryRepository.InsertAsync(category, autoSave: true); // 自动保存更改

                                                                                return category.Id;
                                                                            }



                                                            ★、如果你的意图只不过是在创建、修改、删除后保存更改，建议你使用autoSave 选项就好，而不是使用 CurrentUnitOfWork.SaveChangesAsync:

                                                            

                                                            ★、备注：

                                                                    ①、当一个工作单元结束时，所有更改都会自动保存而没有任何错误。
                                                                    
                                                                        所以，除非你真的需要，否则不要调用SaveChangesAsync()，也不要将autoSave设置为true。

                                                                    ②、如果使用Guid作为主键，则无需在插入时保存更改即可获取生成的id，因为Guid键在应用程序中设置，并且在创建新实体后立即可用。


                                                    (3)、IUnitOfWork（工作单元接口）的其他方法和属性

                                                                    ①、OnCompleted方法获取一个回调操作，该操作在工作单元成功完成时调用（你可以确定所有更改都已保存）。

                                                                    ②、Failed和Disposed事件可用于在UOW失败或被释放时通知。

                                                                    ③、Complete和Rollback方法用于完成（提交）或回滚当前UOW，这通常由ABP内部使用，
                                                                    
                                                                                        但如果你使用IUnitOfWorkManager.Begin方法手动启动事务，则可以使用。

                                                                    ④、Options可用于获取启动UOW时使用的选项。

                                                                    ⑤、Items字典可用于存储和获取同一工作单元内的任意对象，这可以成为实现自定义逻辑的一个点。

                    */

        </script>
    </body>
</html>